package com.yesep.learn.design.behavioral.memento;

/**
 * 备忘录模式（Memento Pattern），又称快照模式（Snapshot Pattern）或Token模式，是GoF（四人帮）提出的23种设计模式之一，属于行为型设计模式。
 * 其核心思想是在不破坏对象封装性的前提下，捕获并保存一个对象的内部状态，以便在将来需要时能够将这些状态恢复到该对象上。
 * <p>
 * 一、基本介绍
 * 定义：备忘录模式允许在不破坏封装性的前提下，捕获一个对象的内部状态，并在该对象之外保存这个状态。这样，以后就可以将该对象恢复到原先保存的状态。
 * <p>
 * 主要角色：
 * <p>
 * 发起人（Originator）：负责创建一个备忘录，记录当前时刻自身的内部状态，并可使用备忘录恢复内部状态。它定义了要创建备忘录数据的接口和恢复备忘录数据的方法。
 * 备忘录（Memento）：用于存储发起人内部状态，以防止发起人以外的其他对象访问备忘录。
 * 备忘录有两个接口，Caretaker只能看到备忘录的窄接口（即只能将备忘录传递给其他对象），而Originator能看到备忘录的宽接口（允许它访问返回到先前状态所需要的所有数据）。
 * 管理者（Caretaker）：负责保存备忘录对象，保证备忘录对象不被其他对象所访问，并且在需要的时候提供备忘录对象给发起人。
 * 二、优点与缺点
 * 优点：
 * <p>
 * 信息封装：备忘录模式可以把复杂的发起人内部信息对其他的对象屏蔽起来，从而可以恰当地保持封装的边界。
 * 简化发起人：发起人不再需要管理和保存其内部状态的一个个版本，客户端可以自行管理他们所需的状态版本。
 * 提供后悔药：当发起人角色的状态改变的时候，有可能这个状态无效，这时候就可以使用暂时存储起来的备忘录将状态复原。
 * 缺点：
 * <p>
 * 资源消耗：如果发起人角色的状态需要完整地存储到备忘录对象中，那么在资源消耗上面备忘录对象会很昂贵。
 * 空间占用：当负责人角色将一个备忘录存储起来的时候，负责人可能并不知道这个状态会占用多大的存储空间，从而无法提醒用户一个操作是否很昂贵。
 * 协议可能无效：如果状态改变的成功率不高的话，不如采取其他模式。
 * 三、应用场景
 * 备忘录模式特别适用于需要实现撤销/重做操作、事务管理或任何需要保存和恢复对象状态的场景。以下是一些具体的应用实例：
 * <p>
 * 文本编辑器撤销功能：在文本编辑器中，每次修改内容前都保存一个状态备忘录，当需要撤销时，从备忘录中恢复相应状态。
 * 游戏进度保存与载入：在游戏开发中，可以利用备忘录模式保存游戏的进度，当玩家需要时，可以恢复到之前的游戏状态。
 * 事务管理：在数据库或应用程序中管理事务时，可以利用备忘录模式在事务开始前保存当前状态，如果事务失败，则恢复到事务开始前的状态。
 * 四、实现示例
 * 由于篇幅限制，这里不直接给出完整的代码实现，但可以提供一个简化的概念性实现框架：
 * <p>
 * 定义备忘录类：用于存储发起人的状态信息。
 * 定义发起人类：负责创建备忘录对象，并记录和恢复自身的状态。
 * 定义管理者类：负责管理备忘录对象，提供添加、删除和获取备忘录对象的方法。
 * 通过这样的框架，可以实现备忘录模式的基本功能，并在实际项目中根据需要进行调整和扩展。
 */
public class Main {
    public static void main(String[] args) {
        Originator document = new Originator("Initial content.");
        Caretaker history = new Caretaker();

        System.out.println("Initial content: " + document.getContent());

        // 用户开始编辑文档
        document.setContent("First edit.");
        System.out.println("After first edit: " + document.getContent());

        // 保存当前状态
        history.push(document.save());

        document.setContent("Second edit.");
        System.out.println("After second edit: " + document.getContent());

        // 保存当前状态
        history.push(document.save());

        // 用户想要撤销上一次的编辑
        IMemento memento = history.pop();
        if (memento != null) {
            document.restore(memento);
            System.out.println("Restored to: " + document.getContent());
        } else {
            System.out.println("No more states to restore.");
        }

        // 再次撤销
        memento = history.pop();
        if (memento != null) {
            document.restore(memento);
            System.out.println("Restored to: " + document.getContent());
        } else {
            System.out.println("No more states to restore.");
        }
    }
}
